﻿using AE.Net.Mail;
using System;
using System.Data;
using System.IO;
using System.Security;
using System.Runtime.Serialization.Formatters.Binary;
using MySql.Data.MySqlClient;
using Microsoft.Exchange.WebServices.Authentication;
using Microsoft.Exchange.WebServices.Data;

namespace MailClient.Mail
{
	public sealed class Connections : IDisposable
	{
		private static readonly System.Lazy<Connections> lazy =
			new System.Lazy<Connections>(() => new Connections());
		private static object synclock = new object();

		public static Connections connections { get { return lazy.Value; } }

		private string SQLusername;
		private string SQLhost;
		private string SQLpass;
		private int Sqlport;
		private string database;
		private DataSet contacts;
		private DataSet schedule;
		private static MySqlConnection Scon;
		

		private Connections()
		{
			lock (synclock)
			{
				#if!DEBUG
				Stream s = File.OpenRead(Properties.Settings.Default.CONFIGPATH);
				#else
				Stream s = File.OpenRead(Properties.Settings.Default.CONFIGPATHTEST);
				#endif
				BinaryFormatter b = new BinaryFormatter();
				ConfigLibrary.Config config = (ConfigLibrary.Config)b.Deserialize(s);
				s.Close();

				config.GetSqlInfo(out SQLhost, out SQLusername, out SQLpass, out database, out Sqlport);
				contacts = new DataSet();
				schedule = new DataSet();

				
				Scon = new MySqlConnection("Database=" + "Mysql" + ";Data Source=" + SQLhost + ";User Id=" + SQLusername + ";Password=" + SQLpass);
				Scon.Open();

				contacts = Contacts;
				DataColumn FullName = contacts.Tables["contacts"].Columns.Add("FullName");
				schedule = Schedule;
			}
		}

		~Connections()
		{
			Scon.Close();
		}

		public void Dispose() { }
		public DataSet Contacts { get { return GetDataSet(ref contacts, "contacts"); } }
		public DataSet Schedule { get { return GetDataSet(ref schedule, "schedule"); } }

		/// <summary>
		/// Loads tables from database specifed in config file
		/// </summary>
		/// <param name="Table">table name to get</param>
		/// <returns></returns>
		protected void GetDataTable(ref DataSet Data, string Table)
		{

			MySqlCommand cmd = new MySqlCommand();
			MySqlDataAdapter sqladapter = new MySqlDataAdapter();

			cmd.CommandText = "Select * from " + Table;
			cmd.Connection = Scon;
			sqladapter.SelectCommand = cmd;
			sqladapter.TableMappings.Add(Table, Table);
			sqladapter.FillSchema(Data, SchemaType.Source, Table);
			sqladapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
			sqladapter.Fill(Data, Table);
			lock (synclock)
				cmd.ExecuteNonQuery();
		}

		/// <summary>
		/// Uses the Database define in the current config file: currently 'Schedule'
		/// </summary>
		/// <param name="Data"></param>
		/// <param name="TableName"></param>
		public void UpdateSQL(DataTable Data, string TableName, string Database)
		{
			MySqlCommand cmd = new MySqlCommand();
			MySqlDataAdapter sqladapter = new MySqlDataAdapter();
			MySqlCommandBuilder cmdbldr = new MySqlCommandBuilder(sqladapter);
			cmd.CommandText = string.Format("USE {0}; Select * from {1}", Database, TableName);
			cmd.Connection = Scon;
			sqladapter.SelectCommand = cmd;
			sqladapter.TableMappings.Add(TableName, TableName);
			sqladapter.FillSchema(Data, SchemaType.Source);
			sqladapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
			lock (synclock)
				sqladapter.Update(Data.GetChanges());
		}

		protected DataSet GetDataSet(ref DataSet Data, string database)
		{
			string mycommand = string.Format("use {0}; show tables", database);
			string result = string.Empty;
			MySqlCommand command = new MySqlCommand(mycommand, Scon);

			lock (synclock)
			{
				using (MySqlDataReader reader = command.ExecuteReader())
				{
					while (reader.Read())
					{
						result += reader.GetString(0) + ";";
					}

					reader.Close();
				}
			}
			string[] TableResult = result.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
			foreach (string Table in TableResult)
			{
				GetDataTable(ref Data, Table);
			}
			return Data;
		}


	}
	
	public sealed class EWSConnection : IDisposable
	{
		private static readonly System.Lazy<EWSConnection> lazy =
			new System.Lazy<EWSConnection>(() => new EWSConnection());
		private static object synclock = new object();

		public static EWSConnection connection { get { return lazy.Value; } }
		private string MailUser;
		private string MailPass;
		private static ExchangeService service;
		
		private EWSConnection()
		{
			lock (synclock) {
				#if!DEBUG
				Stream s = File.OpenRead(Properties.Settings.Default.CONFIGPATH);
				#else
				Stream s = File.OpenRead(Properties.Settings.Default.CONFIGPATHTEST);
				#endif
				BinaryFormatter b = new BinaryFormatter();
				ConfigLibrary.Config config = (ConfigLibrary.Config)b.Deserialize(s);
				s.Close();

				config.GetMailInfo(out MailUser, out MailPass);
				
				IUserData userdata = UserData.CreateUserData(MailUser, MailPass);
				service = Microsoft.Exchange.WebServices.Authentication.Service.ConnectToServiceWithImpersonation(
					UserData.CreateUserData("dplummer@rhaaia.com"), "rha@rhaaia.com", new TraceListener());
			}
		}
		~EWSConnection()
		{
		}

		public void Dispose() { }
		public ExchangeService Service { get { return service; } }
	}
	
	public sealed class ImapConnection : IDisposable
	{
		private static readonly System.Lazy<ImapConnection> lazy =
			new System.Lazy<ImapConnection>(() => new ImapConnection());
		private static object synclock = new object();

		public static ImapConnection connection { get { return lazy.Value; } }
		private string MailHost;
		private string MailUser;
		private string MailPass;
		private int MailPort;
		
		private ImapConnection()
		{
			lock (synclock) {
				#if!DEBUG
				Stream s = File.OpenRead(Properties.Settings.Default.CONFIGPATH);
				#else
				Stream s = File.OpenRead(Properties.Settings.Default.CONFIGPATHTEST);
				#endif
				BinaryFormatter b = new BinaryFormatter();
				ConfigLibrary.Config config = (ConfigLibrary.Config)b.Deserialize(s);
				s.Close();
				config.GetMailInfo(out MailHost, out MailUser, out MailPass, out MailPort);
				
				client = new ImapClient(MailHost, MailUser, MailPass,
				                        ImapClient.AuthMethods.Login, MailPort);
			}
		}
		
		~ImapConnection()
		{
		}

		public void Dispose() { }
		public ImapClient client { get; private set;}
	}
}
